﻿using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using GpgApi;

namespace WgpgCore
{
    public sealed class KeyPhotoNode : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private Image _image;
        private KeyPhoto _photo;
        private Boolean _loading;

        public KeyNode Key { get; private set; }
        public UInt32 Index { get { return _photo.Index; } }

        /// <summary>
        /// The image is loaded asynchronously
        /// </summary>
        public Image Image
        {
            get
            {
                if (_image == null)
                {
                    LoadImage();
                    return null;
                }
                return _image;
            }
        }

        internal KeyPhotoNode(KeyNode key, KeyPhoto photo)
        {
            if (key == null)
                throw new ArgumentNullException("key");

            if (photo == null)
                throw new ArgumentNullException("photo");

            Key = key;
            _photo = photo;
            _image = null;
            _loading = false;
        }

        private void NotifyPropertyChanged(String name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        internal void SetPhoto(KeyPhoto photo)
        {
            if (photo == null)
                throw new ArgumentNullException("photo");

            Boolean propertyIndexChanged = !UInt32.Equals(_photo.Index, photo.Index);
            Boolean propertyImageChanged = false;   // The photo is never modified

            _photo = photo;

            if (propertyIndexChanged) NotifyPropertyChanged("Index");
            if (propertyImageChanged)
            {
                _image = null;
                NotifyPropertyChanged("Image");
            }
        }

        // ----------------------------------------------------------------------------------------

        private void LoadImage()
        {
            if (_loading)
                return;

            _loading = true;
            AddPhotoToLoad(this);
        }

        private void DoLoadImage()
        {
            if (!_loading)
                return;

            GpgLoadPhoto photo = new GpgLoadPhoto(Key.Id, Index);
            photo.Execute();
            _image = photo.Image;

            NotifyPropertyChanged("Image");
        }

        // ----------------------------------------------------------------------------------------

        private static readonly Thread _thread;
        private static readonly AutoResetEvent _loadEvent = new AutoResetEvent(false);
        private static readonly ConcurrentQueue<KeyPhotoNode> _queue = new ConcurrentQueue<KeyPhotoNode>();

        static KeyPhotoNode()
        {
            _thread = new Thread(LoaderThreadLoop)
            {
                Name = "KeyPhotoNodeThread",
                IsBackground = true,
                Priority = ThreadPriority.BelowNormal
            };

            _thread.Start();
        }

        private static void AddPhotoToLoad(KeyPhotoNode photoNode)
        {
            _queue.Enqueue(photoNode);
            _loadEvent.Set();
        }

        private static void LoaderThreadLoop()
        {
            do
            {
                _loadEvent.WaitOne();
                while (ProcessLoadImageStack())
                    Thread.Sleep(1);
            }
            while (true);
        }

        private static Boolean ProcessLoadImageStack()
        {
            KeyPhotoNode p;
            if (_queue.TryDequeue(out p) && p != null)
            {
                p.DoLoadImage();
                return true;
            }

            return false;
        }
    }
}
